/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package org.xhy.sniffer.datacarrier.buffer;


import org.xhy.sniffer.datacarrier.partition.IDataPartitioner;

/**
 * 缓冲区的通道类，包含属于该通道的所有缓冲数据。
 * 它支持多种策略来处理缓冲区满的情况，默认策略是 BLOCKING。
 * 管理多个 buffer
 */
public class Channels<T> {
    private final QueueBuffer<T>[] bufferChannels; // 存放多个缓冲区（队列缓冲区）
    private IDataPartitioner<T> dataPartitioner; // 用于将数据分配到不同通道的分区器
    private final BufferStrategy strategy; // 缓冲区策略，例如阻塞或非阻塞策略
    private final long size; // 总大小，即所有通道的总容量

    // 构造函数，初始化通道大小、缓冲区大小、分区器和策略
    public Channels(int channelSize, int bufferSize, IDataPartitioner<T> partitioner, BufferStrategy strategy) {
        this.dataPartitioner = partitioner; // 初始化数据分区器
        this.strategy = strategy; // 初始化缓冲区策略
        bufferChannels = new QueueBuffer[channelSize]; // 创建指定数量的缓冲区通道
        for (int i = 0; i < channelSize; i++) {
            bufferChannels[i] = new Buffer<>(bufferSize, strategy); // 为每个通道初始化缓冲区
        }
        // size 表示整个通道系统的总容量，防止整数溢出时，将乘法结果强制转换为 long
        size = 1L * channelSize * bufferSize;
    }

    /**
     * 保存数据到适当的缓冲区中。
     * 使用数据分区器决定将数据保存到哪个通道，并处理不同的缓冲策略。
     */
    public boolean save(T data) {
        int index = dataPartitioner.partition(bufferChannels.length, data); // 使用分区器决定要保存到哪个通道
        int retryCountDown = 1; // 默认只重试一次

        // 如果使用的是 IF_POSSIBLE 策略，可以根据分区器允许的最大重试次数进行重试
        if (BufferStrategy.IF_POSSIBLE.equals(strategy)) {
            int maxRetryCount = dataPartitioner.maxRetryCount(); // 获取最大重试次数
            if (maxRetryCount > 1) {
                retryCountDown = maxRetryCount; // 允许多次重试
            }
        }

        // 根据策略和重试次数，尝试将数据保存到缓冲区中
        for (; retryCountDown > 0; retryCountDown--) {
            // 可能不成功
            if (bufferChannels[index].save(data)) { // 如果成功保存数据
                return true; // 返回 true 表示成功
            }
        }
        return false; // 如果保存失败，返回 false
    }

    /**
     * 动态设置数据分区器。
     */
    public void setPartitioner(IDataPartitioner<T> dataPartitioner) {
        this.dataPartitioner = dataPartitioner;
    }

    /**
     * 在运行时覆盖缓冲策略。注意，该方法会一个一个地覆盖每个通道的策略，
     * 因此在调用 setStrategy 时，可能会导致每个通道使用不同的 BufferStrategy。
     */
    public void setStrategy(BufferStrategy strategy) {
        for (QueueBuffer<T> buffer : bufferChannels) { // 遍历所有缓冲区
            buffer.setStrategy(strategy); // 设置新的策略
        }
    }

    /**
     * 获取通道的数量。
     */
    public int getChannelSize() {
        return this.bufferChannels.length; // 返回通道的数量
    }

    /**
     * 获取所有通道的总容量。
     */
    public long size() {
        return size; // 返回总大小
    }

    /**
     * 根据索引获取指定的缓冲区。
     */
    public QueueBuffer<T> getBuffer(int index) {
        return this.bufferChannels[index]; // 返回指定索引的缓冲区
    }
}

